<?php
// Η συμβολική σταθερά "KLISTA_FILENAME" περιέχει το όνομα του αρχείου
// που θεωρείται κλειδαριά για το σύστημα· εφόσον το αρχείο αυτό υπάρχει
// το σύστημα θεωρείται κλειστό και, εφόσον πρόκειται για προεσέγγιση
// ιστού, μπορούμε να το προβάλουμε ως ιστοσελίδα.

define("KLISTA_FILENAME", "lock/klista.php");

// Η συμβολική σταθερά "OWNER_ONOMA" περιέχει το ονοματεπώνυμο του κατέχοντος
// το copyright της εφαρμογής.

define("OWNER_ONOMA", "Panos I. Papadopoulos");

// Η συμβολική σταθερά "OWNER_EMAIL" περιέχει το email του κατέχοντος
// το copyright της εφαρμογής.

define("OWNER_EMAIL", "panos@prefadoros.net");

// Η συμβολική σταθερά "PARASKINIO" περιέχει το όνομα του default αρχείου
// εικόνας παρασκηνίου στο directory "images/paraskinio".

define("PARASKINIO_DEFAULT", "standard.png");

// Η συμβολική σταθερά "FUNCHAT_SERVER" περιέχει το URL της τοποθεσίας
// των funchat multimedia files.

define('FUNCHAT_SERVER', 'http://www.perloc.info/prefadoros/funchatStore/');

mb_internal_encoding("UTF-8");
mb_regex_encoding("UTF-8");

Globals::init();

// Η κλάση "Globals" έχει σκοπό να υιοθετήσει διάφορα global αντικείμενα
// της εφαρμογής, π.χ. το όνομα του server, τον database handler, το login
// name του τρέχοντα χρήστη κλπ. Όλες οι properties και οι μέθοδοι της
// κλάσης είναι static.

class Globals {
	// Η property "init_ok" δείχνει αν έτρεξε η μέθοδος "init".
	// Η μέθοδος πρέπει να τρέχει το πολύ μια φορά.

	private static $init_ok;

	// Η property "session_ok" δείχνει αν έτρεξε η μέθοδος "session".
	// Η μέθοδος πρέπει να τρέχει το πολύ μια φορά.

	private static $session_ok;

	// Η property "server" περιέχει το URL του home directory του server
	// στον οποίο βρίσκεται η εφαρμογή. Πρέπει να τελειώνει με "/", καθώς
	// θα κολλήσουμε subdirectories και file names προκειμένου να
	// προσπελάσουμε άλλα αρχεία και directories της εφαρμογής.

	public static $server;

	// Η property "node_server" περιέχει το URL του node server
	// στον οποίο βρίσκεται η εφαρμογή.

	public static $node_server;

	// Η property "ip" περιέχει την IP του client που αιτείται
	// τις υπηρεσίες της PHP.

	public static $ip;

	// Η property "www" περιέχει το full pathname το βασικού directory
	// της εφαρμογής στον server, π.χ. "/home/panos/Desktop/prefadoros/".

	public static $www;

	// Η propery "klista" είναι TRUE/FALSE και είναι αληθής μόνο εφόσον
	// υπάρχει "lock/klista.php" file. Αν υπάρχει τέτοιο file, τότε
	// θεωρούμε ότι ο ιστότοπος βρίσκεται προσωρινά εκτός λειτουργίας.

	public static $klista;

	// Η property "db" είναι ο database handler μέσω του οποίου προσπελαύνουμε
	// την database της εφαρμογής.

	public static $db;

	// Η property "pektis" περιέχει το login name του χρήστη, ή είναι NULL
	// εφόσον ο χρήστης δεν έχει κάνει login.

	public static $pektis;

	// Η property "klidi" περιέχει το κλειδί της τρέχουσας συνεδρίας, ή είναι
	// NULL εφόσον ο χρήστης δεν έχει κάνει login.

	public static $klidi;

	// Η property "administrator" δείχνει αν βρέθηκε το administrator cookie,
	// οπότε ο χρήστης έχει τα σχετικά προνόμια.

	public static $administrator;

	// Η μέθοδος "init" δημιουργεί το (μοναδικό) instance της κλάσης "Globals".
	// Πρόκειται για global αντικείμενο που περιέχει ως properties χρήσιμα στοιχεία
	// της εφαρμογής, π.χ. το login name του τρέχοντα παίκτη κλπ.

	public static function init() {
		if (self::$init_ok) self::klise_fige("init: reinitialization");
		self::$init_ok = TRUE;

		self::$session_ok = FALSE;
		self::$server = NULL;
		self::$node_server = NULL;
		self::$ip = NULL;
		self::$www = NULL;
		self::$klista = FALSE;
		self::$db = NULL;
		self::$pektis = NULL;
		self::$klidi = NULL;
		self::$administrator = FALSE;

		if (!isset($_SERVER)) self::klise_fige("_SERVER: not set");
		if (!is_array($_SERVER)) self::klise_fige("_SERVER: not an array");

		$server_name = array_key_exists("SERVER_NAME", $_SERVER) ? $_SERVER["SERVER_NAME"] : "localhost";
		switch ($server_name) {
		case "127.0.0.1":
			self::$server = "http://127.0.0.1/prefasix/";
			self::$node_server = "http://127.0.0.1:";
			break;
		case "localhost":
			self::$server = "http://localhost/prefasix/";
			self::$node_server = "http://localhost:";
			break;
		default:
			if ($server_name) print $server_name . ": ";
			self::klise_fige("unknown server");	
		}

		self::get_the_ip();
		self::$www = preg_replace("/lib.standard.php$/", "", __FILE__);
		self::$klista = file_exists(self::$www . KLISTA_FILENAME);
	}

	private static function get_the_ip() {
		self::$ip = "";
		if (array_key_exists("REMOTE_ADDR", $_SERVER)) self::$ip = $_SERVER["REMOTE_ADDR"];
		if (!array_key_exists("HTTP_X_FORWARDED_FOR", $_SERVER)) return;

		$ipf = explode(",", $_SERVER["HTTP_X_FORWARDED_FOR"]);
		if (count($ipf)) self::$ip = $ipf[0];
	}

	// Η μέθοδος "database" μας συνδέει με την database.

	public static function database() {
		if (self::is_klista()) return;

		$dbhost = "localhost";
		$dbname = "prefasix";
		$dbuser = "prefadoros";

		switch (self::$server) {
		case "http://127.0.0.1/prefasix/";
		case "http://localhost/prefasix/";
			break;
		default:
			if (self::$server) print self::$server . ": ";
			self::klise_fige("unknown server (database)");	
		}

		$bekadb = preg_replace("/[^a-zA-Z0-9]/", "", '@p#a@$r*%09##o c$$#@!t@..:');
		self::$db = @mysqli_connect($dbhost, $dbuser, $bekadb);
		if (!self::$db) self::klise_fige("database connection failed (" . @mysqli_connect_error() . ")");

		@mysqli_set_charset(self::$db, "utf8") || self::klise_fige("cannot set character set (database)");
		@mysqli_select_db(self::$db, $dbname) || self::klise_fige("cannot open database (" . $dbname . ")");
	}

	// Η μέθοδος "plires_url" είναι ήσσονος σημασίας και σκοπό έχει τη διευκόλυνση
	// στη γραφή των ονομάτων αρχείων μέσω της πλήρωσης των ονομάτων αυτών με το όνομα
	// του server, π.χ. από "astra" σε "www.prefadoros.gr/astra"

	public static function plires_url($fname = "") {
		return(self::$server . $fname);
	}

	// Η μέθοδος "diavase" είναι ήσσονος σημασίας καθώς υποκαθιστά την "require" και
	// μόνο σκοπό έχει την απλοποίηση των pathnames.

	public static function diavase($file) {
		require self::$www . $file;
	}

	// Ακολουθούν μέθοδοι που έχουν να κάνουν με την επώνυμη ή μη χρήση της
	// εφαρμογής.

	public static function is_pektis() {
		return self::$pektis;
	}

	public static function oxi_pektis() {
		return !self::is_pektis();
	}

	public static function pektis_must() {
		if (self::oxi_pektis()) self::klise_fige("ακαθόριστος παίκτης");
		return self::$pektis;
	}

	// Ακολουθούν μέθοδοι που έχουν να κάνουν με τη χρήση της εφαρμογής με
	// προνόμια διαχειριστού.

	public static function is_administrator() {
		return(self::$administrator === TRUE);
	}

	public static function oxi_administrator() {
		return !self::is_administrator();
	}

	public static function administrator_must() {
		if (self::oxi_administrator()) self::klise_fige("required administrator access");
	}

	// Ακολουθούν μέθοδοι που έχουν να κάνουν με τον αν ο ιστότοπος λειτουργεί
	// ή βρίσκεται προσωρινά εκτός λειτουργίας.

	public static function is_klista() {
		return(self::$klista === TRUE);
	}

	public static function oxi_klista() {
		return !self::is_klista();
	}

	// Η μέθοδος "is_akereos" δέχεται μια μεταβλητή και ελέγχει αν είναι ακέραιος.
	// Πρόκειται για απλή, πλήν χρήσιμη utility method.

	public static function is_akereos($x) {
		if (!isset($x)) return FALSE;
		if (!is_numeric($x)) return FALSE;
		return(intval($x) == $x);
	}

	public static function oxi_akereos($x) {
		return !self::is_akereos($x);
	}

	// Η μέθοδος "is_nai" δέχεται ένα string και επιστρέφει true εφόσον πρόκειται
	// για το string "ΝΑΙ", αλλιώς επιστρέφει false. Η μέθοδος κρίθηκε απαραίτητη
	// λόγω των πολλών enumerated παραμέτρων που δέχονται τιμές ΝΑΙ/ΟΧΙ.

	public static function is_nai($x) {
		return($x === "ΝΑΙ");
	}

	public static function oxi_nai($x) {
		return $self::is_nai($x);
	}

	// Η μέθοδος "query" δέχεται ως πρώτη παράμετρο ένα SQL query και το εκτελεί.
	// Αν υπάρξει οποιοδήποτε δομικό πρόβλημα (όχι σχετικό με την επιτυχία ή μη
	// του query), τότε εκτυπώνεται μήνυμα λάθους και το πρόγραμμα σταματά.

	public static function query($query) {
		$result = @mysqli_query(self::$db, $query);
		if ($result) return $result;

		print "SQL ERROR: " . $query . ": " . @mysqli_error(self::$db);
		self::klise_fige(2);
	}

	public static function sql_errno() {
		return mysqli_errno(self::$db);
	}

	public static function sql_error() {
		return mysqli_error(self::$db);
	}

	// Η μέθοδος "first_row" τρέχει ένα query και επιστρέφει την πρώτη γραμμή των
	// αποτελεσμάτων απελευθερώνοντας τυχόν άλλα αποτελέσματα.

	public static function first_row($query, $idx = MYSQLI_BOTH) {
		$result = self::query($query);
		while ($row = @mysqli_fetch_array($result, $idx)) {
			@mysqli_free_result($result);
			break;
		}

		return $row;
	}

	public static function insert_id() {
		return @mysqli_insert_id(self::$db);
	}

	public static function affected_rows() {
		return @mysqli_affected_rows(self::$db);
	}

	public static function autocommit($on_off) {
		@mysqli_autocommit(self::$db, $on_off) || self::klise_fige("autocommit failed");
	}

	public static function commit() {
		@mysqli_commit(self::$db) || self::klise_fige("commit failed");
	}

	public static function rollback() {
		@mysqli_rollback(self::$db) || self::klise_fige("rollback failed");
	}

	// Η μέθοδος "klidoma" επιχειρεί να θέσει κάποιο database lock που καθορίζεται
	// από το tag που περνάμε ως πρώτη παράμετρο. By default η μέθοδος θεωρεί ότι
	// δεν μπορεί να κλειδώσει εφόσον το κλείδωμα αποτύχει για 2 δευτερόλεπτα, αλλά
	// μπορούμε να περάσουμε μεγαλύτερο ή μικρότερο χρονικό διάστημα ως δεύτερη
	// παράμετρο.
	//
	// Η μέθοδος επιστρέφει TRUE εφόσον το κλείδωμα επιτύχει, αλλιώς επιστρέφει
	// FALSE.

	public static function klidoma($tag, $timeout = 2) {
		$query = "SELECT GET_LOCK(" . self::asfales_sql($tag) . ", " . $timeout . ")";
		$row = self::first_row($query, MYSQLI_NUM);
		if (!$row) return FALSE;
		return($row[0] == 1);
	}

	// Η μέθοδος "xeklidoma" ξεκλειδώνει κάποιο κλείδωμα που θέσαμε με την μέθοδο
	// "klidoma". Το tag του κλειδώματος που θα ξεκλειδωθεί περνιέται ως πρώτη
	// παράμετρος, ενώ ως δεύτερη παράμετρος μπορεί να περάσει TRUE/FALSE value
	// που δείχνει αν πριν το ξεκλείδωμα θα γίνει commit ή rollback αντίστοιχα.
	// Αν δεν περαστεί δεύτερη παράμετρος, τότε δεν γίνεται ούτε commit ούτε
	// rollback, οπότε μπορούμε να συνεχίσουμε στα πλαίσια της τρέχουσας
	// transaction.

	public static function xeklidoma($tag, $commit = NULL) {
		if (isset($commit)) {
			if ($commit) @mysqli_commit(self::$db);
			else @mysqli_rollback(self::$db);
		}

		$query = "DO RELEASE_LOCK(" . self::asfales_sql($tag) . ")";
		@mysqli_query(self::$db, $query);
	}

	// Η μέθοδος "klise_fige" κλείνει τη σύνδεση με την database και διακόπτει
	// το πρόγραμμα. Μπορούμε να περάσουμε μήνυμα το οποίο θα εκτυπωθεί πριν τη
	// διακοπή του προγράμματος. Μπορούμε, ακόμη, να περάσουμε ως παράμετρο μια
	// αριθμητική τιμή η οποία θα χρησιμοποιηθεί ως exit status.

	public static function klise_fige($msg = NULL) {
		if (isset(self::$db)) {
			@mysqli_kill(self::$db, @mysqli_thread_id(self::$db));
			@mysqli_close(self::$db);
		}

		if (!isset($msg)) {
			$stat = 0;
		}
		elseif (is_int($msg)) {
			$stat = (int)$msg;
		}
		else {
			print $msg;
			$stat = 2;
		}

		while (@ob_end_flush());
		die($stat);
	}

	// Η μέθοδος "perastike" δέχεται ως παράμετρο ένα string και επιστρέφει
	// TRUE εφόσον έχει περαστεί αντίστοιχη GET/POST παράμετρος.

	public static function perastike($key) {
		return(isset($_REQUEST) && is_array($_REQUEST) && array_key_exists($key, $_REQUEST));
	}

	public static function den_perastike($key) {
		return !self::perastike($key);
	}

	// Η μέθοδος "perastike_must" επιτάσσει να έχει περαστεί η GET/POST παράμετρος που
	// περνάμε ως πρώτη παράμετρο. Αν έχει περαστεί η παράμετρος, τότε επιστρέφεται η
	// τιμή της παραμέτρου, αλλιώς το πρόγραμμα σταματά.

	public static function perastike_must($key, $msg = NULL) {
		if (self::perastike($key)) return $_REQUEST[$key];

		print isset($msg) ? $msg : $key . ": δεν περάστηκε παράμετρος";
		self::klise_fige(2);
	}

	// Η μέθοδος "session_set" δέχεται ως παράμετρο ένα string και επιστρέφει
	// TRUE εφόσον υπάρχει το αντίστοιχο session cookie.

	public static function session_set($tag) {
		if (!isset($_SESSION)) self::klise_fige("_SESSION: not set");
		if (!is_array($_SESSION)) self::klise_fige("_SESSION: not an array");

		return array_key_exists($tag, $_SESSION);
	}

	// Η μέθοδος "asfales_sql" δέχεται ένα string και επιστρέφει το ίδιο string
	// αλλά τροποποιημένο ώστε να μην τίθεται θέμα SQL injection. Γίνεται επίσης
	// και διαφυγή των quotes. Το string επιστρέφεται μαζί με τα quotes που το
	// περικλείουν, εκτός και αν περάσουμε δεύτερη (false) παράμετρο.

	public static function asfales_sql($s, $string = TRUE) {
		if (get_magic_quotes_gpc()) $s = stripslashes($s);
		if (isset(self::$db)) $s = @mysqli_real_escape_string(self::$db, $s);
		return($string ? "'" . $s . "'" : $s);
	}

	// Η μέθοδος "asfales_json" δέχεται ως παράμετρο ένα string και το επιστρέφει
	// τροποιημένο ώστε να μπορεί με ασφάλεια να ενταχθεί ως rvalue σε json objects
	// μαζί με τα quotes.

	public static function asfales_json($s) {
		$s = str_replace('\\', '\\\\', $s);
		return "'" . str_replace("'", "\'", $s) . "'";
	}

	// Η μέθοδος "akirosi_script" χρησιμοποιείται για να ακυρώσει τυχόν
	// ενσωματωμένο javascript κώδικα σε μηνύματα και συζητήσεις, και
	// το επιτυγχάνει εισάγοντας χαρακτήρα μηδενικού πλάτους πριν τη
	// λέξη script.

	public static function akirosi_script($s) {
		return preg_replace("/script/i", "&#8203;script", $s);
	}

	public static function email_check($email) {
		return filter_var($email, FILTER_VALIDATE_EMAIL) ? $email : NULL;
	}

	public static function xroniki_stigmi($ts, $offset = 0, $format = "d/m/Y, h:i", $prin = TRUE) {
		$ts += $offset;
		if ($prin) {
			$dif = time() - $ts;
			if ($dif < 60) return "τώρα";

			if ($dif < 3600) {
				$x = round($dif / 60);
				return("πριν " . $x . " λεπτ" . ($x < 2 ? "ό" : "ά"));
			}

			if ($dif < 86400) {
				$x = round($dif / 3600);
				return("πριν " . $x . " ώρ" . ($x < 2 ? "α" : "ες"));
			}
		}

		return date($format, $ts);
	}

	public static function header_data() {
		header('Content-type: text/plain; charset=utf-8');
	}

	public static function header_json() {
		header('Content-Type: application/json; charset=utf-8');
	}

	public static function header_html() {
		header('Content-type: text/html; charset=utf-8');
	}

	public static function session() {
		if (self::$session_ok) self::klise_fige("session: reinitialization");
		self::$session_ok = TRUE;

		// 24 * 7 * 3600 = 604800
		ini_set("session.gc_maxlifetime", "604800");
		session_set_cookie_params(604800);
		session_start();

		// Αν ο ιστότοπος είναι κλειστός αποφεύγουμε την επώνυμη χρήση
		// και μάλιστα καταργούμε και τα σχετικά διαπιστευτήρια.

		if (self::is_klista()) {
			self::exodos();
		}
		else {
			if (self::session_set("pektis")) self::$pektis = $_SESSION["pektis"];
			if (self::session_set("klidi")) self::$klidi = $_SESSION["klidi"];
		}

		// Ακόμη και όταν ο ιστότοπος είναι κλειστός επιτρέπουμε τη
		// χρήση ως administrator.

		if (self::session_set("administrator")) self::$administrator = self::session_set("administrator");
	}

	public static function exodos() {
		Sinedria::arxio() || Globals::klise_fige();

		self::$pektis = NULL;
		self::$klidi = NULL;

		if (!isset($_SESSION)) return;
		if (!is_array($_SESSION)) return;

		unset($_SESSION["pektis"]);
		unset($_SESSION["klidi"]);
		unset($_SESSION["paraskinio"]);
	}

	// Η μέθοδος "random_string" επιστρέφει ένα string συγκεκριμένου μήκους, αποτελούμενο
	// από χαρακτήρες που λαμβάνονται από παλέτα.

	public static function random_string($mikos, $paleta =
		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") {
		$s = "";
		$n = strlen($paleta) - 1;
		for ($i = 0; $i < $mikos; $i++) {
			$s .= $paleta[mt_rand(0, $n)];
		}

		return $s;
	}

	public static function update_peparam($pektis, $param, $timi) {
		$spektis = self::asfales_sql($pektis);
		$sparam = self::asfales_sql($param);
		$stimi = self::asfales_sql($timi);

		$query = "REPLACE `peparam` (`pektis`, `param`, `timi`) VALUES (" .
			$spektis . ", " . $sparam . ", " . $stimi . ")";
		self::query($query, FALSE);

		$query = "SELECT `timi` FROM `peparam` WHERE (`pektis` = " . $spektis .
			") AND (`param` = " . $sparam . ") LIMIT 1";
		$row = self::first_row($query, MYSQLI_NUM);
		if (!$row) return FALSE;
		return($row[0] == $timi);
	}
}

class Pektis {
	public $login;
	public $egrafi;
	public $onoma;
	public $email;
	public $kodikos;
	public $poll;
	public $peparam;

	public function __construct($login = NULL, $peparam = FALSE, $kodikos = NULL) {
		$this->login = NULL;
		$this->egrafi = NULL;
		$this->onoma = NULL;
		$this->email = NULL;
		$this->kodikos = NULL;
		$this->poll = NULL;

		$this->peparam = NULL;

		if ($login === NULL) return;

		$query = "SELECT * FROM `pektis` WHERE (`login` = BINARY " . Globals::asfales_sql($login) . ")";
		if (isset($kodikos)) $query .= " AND (`kodikos` = BINARY '" . sha1($kodikos) . "')";
		$query .= " LIMIT 1";
		$result = Globals::query($query);
		while ($row = @mysqli_fetch_array($result, MYSQLI_ASSOC)) {
			$this->set_row($row);
		}
		@mysqli_free_result($result);

		if (!isset($this->login)) return;

		if ($peparam) $this->get_peparam();
	}

	public function set_row($row) {
		$this->login = $row["login"];
		$this->egrafi = $row["egrafi"];
		$this->onoma = $row["onoma"];
		$this->email = Globals::email_check($row["email"]);
		$this->kodikos = $row["kodikos"];
		$this->poll = $row["poll"];
		return $this;
	}

	public function get_peparam() {
		$this->peparam = array();
		$query = "SELECT `param`, `timi` FROM `peparam` WHERE `pektis` = BINARY " .
			Globals::asfales_sql($this->login);
		$result = Globals::query($query);
		while ($row = @mysqli_fetch_array($result, MYSQLI_NUM)) {
			switch ($row[0]) {
			case "ΑΞΙΩΜΑ":
				switch ($row[1]) {
				case "VIP":		$row[1] = 1; break;
				case "ΕΠΟΠΤΗΣ":		$row[1] = 2; break;
				case "ΔΙΑΧΕΙΡΙΣΤΗΣ":	$row[1] = 3; break;
				case "ADMINISTRATOR":	$row[1] = 4; break;
				case "ΠΡΟΕΔΡΟΣ":	$row[1] = 5; break;
				default:		$row[1] = NULL; break;
				}
				break;
			case "ΚΑΤΑΣΤΑΣΗ":
				switch ($row[1]) {
				case "ΑΠΑΣΧΟΛΗΜΕΝΟΣ":
					$row[1] = "B";
					break;
				default:
					$row[1] = NULL;
					break;
				}
				break;
			case "ΑΣΟΙ":
				$row[1] = Globals::is_nai($row[1]) ? NULL : FALSE;
				break;
			case "ΠΑΣΟ":
				$row[1] = Globals::is_nai($row[1]) ? TRUE : NULL;
				break;
			case "ΤΕΛΕΙΩΜΑ":
				switch ($row[1]) {
				case "ΑΝΙΣΟΡΡΟΠΟ":	$row[1] = "U"; break;
				case "ΔΙΚΑΙΟ":		$row[1] = "F"; break;
				default:		$row[1] = NULL; break;
				}
				break;
			case "ΠΛΑΤΗ":
				switch ($row[1]) {
				case "ΚΟΚΚΙΝΟ":		$row[1] = "R"; break;
				case "ΤΥΧΑΙΟ":		$row[1] = "N"; break;
				default:		$row[1] = NULL; break;
				}
				break;
			case "ΠΑΡΑΣΚΗΝΙΟ":
				if ($row[1] == PARASKINIO_DEFAULT) $row[1] = NULL;
				break;
			case "BLOCKIMAGE":
				$row[1] = Globals::is_nai($row[1]) ? TRUE : NULL;
				break;
			case "MOVIETIME":
				switch ($row[1]) {
				case "ΠΡΑΓΜΑΤΙΚΟΣ":
					$row[1] = "R";
					break;
				default:
					$row[1] = NULL;
					break;
				}
				break;
			case "MOVIESCALE":
				if (self::oxi_akereos($row[1])) $row[1] = NULL;
				else if ($row[1] < 1) $row[1] = NULL;
				else $row[1] = intval($row[1]);
				break;
			default:
				$row[1] = NULL;
				break;
			}

			if ($row[1] === NULL) unset($this->peparam[$row[0]]);
			else $this->peparam[$row[0]] = $row[1];
		}
		@mysqli_free_result($result);

		return $this;
	}

	public function asoi() {
		if (!isset($this->peparam)) return NULL;
		if (!array_key_exists("ΑΣΟΙ", $this->peparam)) return TRUE;
		return $this->peparam["ΑΣΟΙ"];
	}

	public function paso() {
		if (!isset($this->peparam)) return NULL;
		if (!array_key_exists("ΠΑΣΟ", $this->peparam)) return FALSE;
		return $this->peparam["ΠΑΣΟ"];
	}

	public function postel() {
		if (!isset($this->peparam)) return NULL;

		$default = "ΚΑΝΟΝΙΚΟ";
		if (!array_key_exists("ΤΕΛΕΙΩΜΑ", $this->peparam)) return $default;

		switch ($this->peparam["ΤΕΛΕΙΩΜΑ"]) {
		case "U": return "ΑΝΙΣΟΡΡΟΠΟ";
		case "F": return "ΔΙΚΑΙΟ";
		}

		return $default;
	}

	public function katastasi() {
		if (!isset($this->peparam)) return NULL;

		$default = "ΔΙΑΘΕΣΙΜΟΣ";
		if (!array_key_exists("ΚΑΤΑΣΤΑΣΗ", $this->peparam)) return $default;

		switch ($this->peparam["ΚΑΤΑΣΤΑΣΗ"]) {
		case "B": return "ΑΠΑΣΧΟΛΗΜΕΝΟΣ";
		}

		return $default;
	}

	public function plati() {
		if (!isset($this->peparam)) return NULL;

		$default = "ΜΠΛΕ";
		if (!array_key_exists("ΠΛΑΤΗ", $this->peparam)) return $default;

		switch ($this->peparam["ΠΛΑΤΗ"]) {
		case "R": return "ΚΟΚΚΙΝΟ";
		case "N": return "ΤΥΧΑΙΟ";
		}

		return $default;
	}

	public function paraskinio() {
		if (!isset($this->peparam)) return NULL;
		if (!array_key_exists("ΠΑΡΑΣΚΗΝΙΟ", $this->peparam)) return PARASKINIO_DEFAULT;
		return $this->peparam["ΠΑΡΑΣΚΗΝΙΟ"];
	}

	public function get_profinfo($sxoliastis = NULL) {
		if (!$this->login) return NULL;

		if ($sxoliastis === NULL) $sxoliastis = $this->login;
		$query = "SELECT `kimeno` FROM `profinfo` WHERE (`pektis` = BINARY " .
			Globals::asfales_sql($this->login) . ") AND (`sxoliastis` = BINARY " .
			Globals::asfales_sql($sxoliastis) . ") LIMIT 1";
		$result = Globals::query($query);
		$kimeno = NULL;
		while ($row = @mysqli_fetch_array($result, MYSQLI_NUM)) {
			$kimeno = $row[0];
		}
		@mysqli_free_result($result);

		return $kimeno;
	}

	public function set_profinfo($kimeno = "", $sxoliastis = NULL) {
		if (!$this->login) return FALSE;

		if ($sxoliastis === NULL) $sxoliastis = $this->login;
		$query = "REPLACE `profinfo` (`pektis`, `sxoliastis`, `kimeno`) VALUES (" .
			Globals::asfales_sql($this->login) . ", " . Globals::asfales_sql($sxoliastis) .
			", " . Globals::asfales_sql($kimeno) . ")";
		Globals::query($query);
		return($this->get_profinfo() == $kimeno);
	}
}

class Trapezi {
	public $kodikos;
	public $stisimo;
	public $pektis1;
	public $apodoxi1;
	public $pektis2;
	public $apodoxi2;
	public $pektis3;
	public $apodoxi3;
	public $poll;
	public $arxio;
	public $trparam;

	public function __construct($kodikos = NULL, $trparam = FALSE,
		$prosklisi = FALSE, $theatis = FALSE, $dianomi = FALSE) {
		$this->kodikos = NULL;
		$this->stisimo = NULL;
		$this->pektis1 = NULL;
		$this->apodoxi1 = NULL;
		$this->pektis2 = NULL;
		$this->apodoxi2 = NULL;
		$this->pektis3 = NULL;
		$this->apodoxi3 = NULL;
		$this->poll = NULL;
		$this->arxio = NULL;

		$this->trparam = NULL;
		$this->prosklisi = NULL;
		$this->theatis = NULL;
		$this->dianomi = NULL;

		if (!self::is_akereos($kodikos)) return;

		$query = "SELECT * FROM `trapezi` WHERE `kodikos` = " . $kodikos . " LIMIT 1";
		$result = Globals::query($query);
		while ($row = @mysqli_fetch_array($result, MYSQLI_ASSOC)) {
			$this->set_row($row);
		}
		@mysqli_free_result($result);

		if (!isset($this->kodikos)) return;

		if ($trparam) $this->get_trparam();
		if ($prosklisi) $this->get_prosklisi();
		if ($theatis) $this->get_theatis();
		if ($dianomi) $this->get_dianomi();
	}

	public function set_row($row) {
		$this->kodikos = $row["kodikos"];
		$this->pektis1 = $row["pektis1"];
		$this->apodoxi1 = $row["apodoxi1"];
		$this->pektis2 = $row["pektis2"];
		$this->apodoxi2 = $row["apodoxi2"];
		$this->pektis3 = $row["pektis3"];
		$this->apodoxi3 = $row["apodoxi3"];
		$this->poll = $row["poll"];
		$this->arxio = $row["arxio"];
		return $this;
	}

	public function get_trparam() {
		$this->trparam = array();
		$query = "SELECT `param`, `timi` FROM `trparam` WHERE `trapezi` = " . $this->kodikos;
		$result = Globals::query($query);
		while ($row = @mysqli_fetch_array($result, MYSQLI_NUM)) {
			switch ($row[0]) {
			case "ΚΑΣΑ":
				if (!self::is_akereos($row[1])) $row[1] = NULL;
				else $row[1] = intval($row[1]);
				break;
			case "ΙΔΙΟΚΤΗΤΟ":
			case "ΠΑΣΟ":
			case "ΠΡΙΒΕ":
			case "ΦΙΛΙΚΗ":
			case "ΕΠΕΤΕΙΑΚΗ":
				$row[1] = Globals::is_nai($row[1]) ? TRUE : NULL;
				break;
			case "ΑΣΟΙ":
			case "ΑΝΟΙΚΤΟ":
				$row[1] = Globals::is_nai($row[1]) ? NULL : FALSE;
				break;
			case "ΤΕΛΕΙΩΜΑ":
				switch ($row[1]) {
				case "ΑΝΙΣΟΡΡΟΠΟ":	$row[1] = "U"; break;
				case "ΔΙΚΑΙΟ":		$row[1] = "F"; break;
				default:		$row[1] = NULL; break;
				}
				break;
			default:
				$row[1] = NULL;
				break;
			}

			if ($row[1] === NULL) unset($this->trparam[$row[0]]);
			else $this->trparam[$row[0]] = $row[1];
		}
		@mysqli_free_result($result);

		return $this;
	}

	public function get_prosklisi() {
		$this->prosklisi = array();
		$query = "SELECT * FROM `prosklisi` WHERE `trapezi` = " . $this->kodikos . " ORDER BY `kodikos`";
		$result = Globals::query($query);
		while ($row = @mysqli_fetch_array($result, MYSQLI_ASSOC)) {
			$this->prosklisi[$row["kodikos"]] = (new Prosklisi())->set_row($row);
		}
		@mysqli_free_result($result);

		return $this;
	}

	public function get_theatis() {
		$this->theatis = array();
		$query = "SELECT `pektis`, `thesi` FROM `sinedria` WHERE (`trapezi` = " .
			$this->kodikos . ") AND (`simetoxi` LIKE 'ΘΕΑΤΗΣ')";
		$result = Globals::query($query);
		while ($row = @mysqli_fetch_array($result, MYSQLI_NUM)) {
			$this->theatis[$row[0]] = $row[1];
		}
		@mysqli_free_result($result);

		return $this;
	}

	public function get_dianomi() {
		$this->dianomi = array();
		$query = "SELECT * FROM `dianomi` WHERE `trapezi` = " . $this->kodikos . " ORDER BY `kodikos`";
		$result = Globals::query($query);
		while ($row = @mysqli_fetch_array($result, MYSQLI_ASSOC)) {
			$this->dianomi[] = (new Dianomi())->set_row($row);
		}
		@mysqli_free_result($result);

		return $this;
	}

	public function set_pistosi() {
		$pistosi = 0;
		if (!isset($this->dianomi)) $this->get_dianomi();
		for ($i = count($this->dianomi - 1); $i >= 0; $i--) {
			$pistosi += $this->dianomi[$i]->kasa1 + $this->dianomi[$i]->kasa2 + $this->dianomi[$i]->kasa3;
		}

		$this->trparam["ΠΙΣΤΩΣΗ"] = $pistosi;
		return $this;
	}
}

class Prosklisi {
	public $kodikos;
	public $trapezi;
	public $apo;
	public $pros;
	public $epidosi;

	public function __construct($kodikos = NULL, $energia = FALSE) {
		$this->kodikos = NULL;
		$this->trapezi = NULL;
		$this->apo = NULL;
		$this->pros = NULL;
		$this->epidosi = NULL;

		if (!self::is_akereos($kodikos)) return;

		$query = "SELECT * FROM `prosklisi` WHERE `kodikos` = " . $kodikos . " LIMIT 1";
		$result = Globals::query($query);
		while ($row = @mysqli_fetch_array($result, MYSQLI_ASSOC)) {
			$this->set_row($row);
		}
		@mysqli_free_result($result);
	}

	public function set_row($row) {
		$this->kodikos = $row["kodikos"];
		$this->trapezi = $row["trapezi"];
		$this->apo = $row["apo"];
		$this->pros = $row["pros"];
		$this->epidosi = $row["epidosi"];
		return $this;
	}
}

class Dianomi {
	public $kodikos;
	public $trapezi;
	public $dealer;
	public $kasa1;
	public $metrita1;
	public $kasa2;
	public $metrita2;
	public $kasa3;
	public $metrita3;
	public $enarxi;
	public $telos;
	public $energia;

	public function __construct($kodikos = NULL, $energia = FALSE) {
		$this->kodikos = NULL;
		$this->trapezi = NULL;
		$this->enarxi = NULL;
		$this->dealer = NULL;
		$this->kasa1 = NULL;
		$this->metrita1 = NULL;
		$this->kasa2 = NULL;
		$this->metrita2 = NULL;
		$this->kasa3 = NULL;
		$this->metrita3 = NULL;
		$this->telos = NULL;

		$this->energia = NULL;

		if (!self::is_akereos($kodikos)) return;

		$query = "SELECT * FROM `dianomi` WHERE `kodikos` = " . $kodikos . " LIMIT 1";
		$result = Globals::query($query);
		while ($row = @mysqli_fetch_array($result, MYSQLI_ASSOC)) {
			$this->set_row($row);
		}
		@mysqli_free_result($result);

		if (!isset($this->kodikos)) return;

		if ($energia) $this->get_energia();
	}

	public function set_row($row) {
		$this->kodikos = $row["kodikos"];
		$this->trapezi = $row["trapezi"];
		$this->enarxi = $row["enarxi"];
		$this->dealer = $row["dealer"];
		$this->kasa1 = $row["kasa1"];
		$this->metrita1 = $row["metrita1"];
		$this->kasa2 = $row["kasa2"];
		$this->metrita2 = $row["metrita2"];
		$this->kasa3 = $row["kasa3"];
		$this->metrita3 = $row["metrita3"];
		$this->telos = $row["telos"];
		return $this;
	}

	public function get_energia() {
		$this->energia = array();
		$query = "SELECT * FROM `energia` WHERE `dianomi` = " . $this->kodikos . " ORDER BY `kodikos`";
		$result = Globals::query($query);
		while ($row = @mysqli_fetch_array($result, MYSQLI_NUM)) {
			$this->energia[] = (new Energia())->set_row($row);
		}
		@mysqli_free_result($result);

		return $this;
	}
}

class Sinedria {
	// Η static μέθοδος "arxio" αρχειοθετεί την τρέχουσα συνεδρία του παίκτη
	// του οποίου το login name περνάμε ως παράμετρο. Αν δεν περάσουμε παίκτη
	// υποτίθεται ο τρέχων παίκτης και σ' αυτή την περίπτωση γίνεται έλεγχος
	// διαπιστευτηρίων.

	public static function arxio($pektis = NULL) {
		if (isset($pektis)) $klidi = FALSE;
		else {
			$pektis = Globals::is_pektis();
			if (!isset($pektis)) {
				print "Ακαθόριστος παίκτης κατά την αρχειοθέτηση συνεδρίας";
				return FALSE;
			}

			if (Globals::session_set("klidi")) $klidi = $_SESSION["klidi"];
			else {
				print "Ακαθόριστο κλειδί συνεδρίας κατά την αρχειοθέτηση";
				return FALSE;
			}
		}

		// Επιχειρούμε αρχειοθέτηση της τρέχουσας συνεδρίας, εφόσον αυτή υπάρχει.
		$slogin = Globals::asfales_sql($pektis);
		$query = "INSERT INTO `istoriko` (`pektis`, `ip`, `isodos`, `exodos`) " .
			"SELECT `pektis`, `ip`, `isodos`, NOW() FROM `sinedria` " .
			"WHERE (`pektis` = BINARY " . $slogin . ")";
		if ($klidi !== FALSE) $query .= " AND (`klidi` = BINARY " . Globals::asfales_sql($klidi) . ")";
		Globals::query($query);
		if (Globals::affected_rows() <= 0) return TRUE;

		// Εισήχθη εγγραφή στο μητρώο συνεδριών, επομένως υπήρχε τρέχουσα συνεδρία
		// για τον εν λόγω παίκτη και αυτή πρέπει να διαγραφεί.
		$query = "DELETE FROM `sinedria` WHERE `pektis` = BINARY " . $slogin;
		Globals::query($query);
		if (Globals::affected_rows() > 0) return TRUE;

		print 'Απέτυχε η αρχειοθέτηση συνεδρίας για τον παίκτη "' . $pektis . '"';
		return FALSE;
	}

	// Η static μέθοδος "nea" δημιουργεί νέα συνεδρία για τον παίκτη του οποίου
	// το login name περνάμε ως παράμετρο.

	public static function nea($pektis = NULL) {
		if (!isset($pektis)) {
			print "Ακαθόριστος παίκτης κατά τη δημιουργία νέας συνεδρίας";
			return FALSE;
		}
		// Επιχειρούμε να αρχειοθετήσουμε πρώτα τυχόν ενεργή συνεδρία για τον
		// εν λόγω παίκτη.
		if (!self::arxio($pektis)) return FALSE;

		// Αυτή τη στιγμή δεν έχουμε ενεργή συνεδρία για τον εν λόγω παίκτη και
		// δημιουργούμε νέα συνεδρία για τον παίκτη αυτόν. Εφόσον δημιουργηθεί
		// επιτυχώς η νέα συνεδρία, επιστρέφουμε το κλειδί που είναι τυχαίο string
		// μήκους 10 χαρακτήρων, αλλιώς επιστρέφουμε FALSE.

		$klidi = Globals::random_string(10);
		$slogin = Globals::asfales_sql($pektis);
		$query = "INSERT INTO `sinedria` (`pektis`, `klidi`, `ip`, `poll`) VALUES " .
			"(" . $slogin . ", '" . $klidi . "', '" . Globals::$ip . "', NOW())";
		Globals::query($query);
		if (Globals::affected_rows() == 1) return $klidi;

		print 'Απέτυχε η δημιουργία νέας συνεδρίας για τον παίκτη "' . $pektis . '"';
		return FALSE;
	}
}
?>
